package com.easydict.config;

import com.easydict.annotation.EasyDict;
import com.easydict.core.DefaultPropertyWriterFactory;
import com.easydict.core.PropertyWriterFactory;
import com.easydict.core.SerializationContext;
import com.easydict.spi.DictionaryResolver;
import com.easydict.writer.EnhancedDictionaryPropertyWriter;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 高级Bean序列化修改器
 * 使用工厂模式和缓存机制提供高性能的字典转换功能
 */
public class DicTypeBeanSerializerModifier extends BeanSerializerModifier {

    private static final AtomicLong MODIFICATION_COUNTER = new AtomicLong(0);

    private final DictionaryResolver primaryResolver;
    private final PropertyWriterFactory writerFactory;
    private final ConcurrentHashMap<String, SerializationContext> contextCache;
    private final ModificationMetrics metrics;
    // 保留构造参数用于向工厂传递，但本类自身不再持有该字段以避免未使用告警

    public DicTypeBeanSerializerModifier(DictProvider dictProvider) {
        this(dictProvider, "Dict");
    }

    public DicTypeBeanSerializerModifier(DictProvider dictProvider, String configuredSuffix) {
        this.primaryResolver = new com.easydict.resolver.CompositeDictionaryResolver(
                new com.easydict.resolver.EnumDictionaryResolver(),
                new com.easydict.resolver.DelegatingDictionaryResolver(dictProvider)
        );
        this.writerFactory = new DefaultPropertyWriterFactory(configuredSuffix);
        this.contextCache = new ConcurrentHashMap<>();
        this.metrics = new ModificationMetrics();
    }

    @Override
    public List<BeanPropertyWriter> changeProperties(
            SerializationConfig config,
            BeanDescription beanDesc,
            List<BeanPropertyWriter> beanProperties) {

        MODIFICATION_COUNTER.incrementAndGet();
        long startTime = System.nanoTime();

        try {
            metrics.incrementModifications();

            SerializationContext context = getOrCreateContext(config, beanDesc);

            // 第一遍：为所有带注解且有效的字段创建增强写入器，并收集将要生成的字典字段名
            java.util.Map<String, BeanPropertyWriter> enhancedByOriginalName = new java.util.HashMap<>();
            java.util.Set<String> generatedDictFieldNames = new java.util.HashSet<>();

            for (BeanPropertyWriter originalWriter : beanProperties) {
                if (!writerFactory.supports(originalWriter, context)) {
                    continue;
                }
                EasyDict annotation = originalWriter.getAnnotation(EasyDict.class);
                if (annotation != null && isValidAnnotation(annotation)) {
                    BeanPropertyWriter enhanced = writerFactory.createDictionaryWriter(
                            originalWriter, annotation, primaryResolver, context);
                    enhancedByOriginalName.put(originalWriter.getName(), enhanced);

                    if (enhanced instanceof EnhancedDictionaryPropertyWriter) {
                        String dictName = ((EnhancedDictionaryPropertyWriter) enhanced).getDictionaryFieldName();
                        if (dictName != null) {
                            generatedDictFieldNames.add(dictName);
                        }
                    }
                }
            }

            // 第二遍：构建最终写入器列表
            List<BeanPropertyWriter> enhancedWriters = new ArrayList<>(beanProperties.size());
            for (BeanPropertyWriter originalWriter : beanProperties) {
                // 过滤掉将由增强写入器生成的字典字段对应的原生 writer，避免覆盖
                if (generatedDictFieldNames.contains(originalWriter.getName())) {
                    continue;
                }

                BeanPropertyWriter enhanced = enhancedByOriginalName.get(originalWriter.getName());
                if (enhanced != null) {
                    metrics.incrementDictionaryWriters();
                    enhancedWriters.add(enhanced);
                } else {
                    metrics.incrementStandardWriters();
                    enhancedWriters.add(writerFactory.createStandardWriter(originalWriter, context));
                }
            }

            metrics.recordProcessingTime(System.nanoTime() - startTime);
            return enhancedWriters;

        } catch (Exception e) {
            metrics.incrementErrors();
            // 发生错误时返回原始属性列表
            return new ArrayList<>(beanProperties);
        }
    }

    private SerializationContext getOrCreateContext(SerializationConfig config,
                                                   BeanDescription beanDesc) {
        String contextKey = generateContextKey(config, beanDesc);

        return contextCache.computeIfAbsent(contextKey, key ->
                SerializationContext.builder()
                        .config(config)
                        .beanDescription(beanDesc)
                        .build());
    }

    // 保留旧逻辑的方法已不再使用

    private boolean isValidAnnotation(EasyDict annotation) {
        boolean hasTypeCode = annotation.dictType() != null && !annotation.dictType().trim().isEmpty();
        boolean hasEnum = (annotation.enumClass() != null && annotation.enumClass() != Void.class)
                || (annotation.enumClassName() != null && !annotation.enumClassName().trim().isEmpty());
        return hasTypeCode || hasEnum;
    }

    private String generateContextKey(SerializationConfig config, BeanDescription beanDesc) {
        return beanDesc.getBeanClass().getName() + "@" + System.identityHashCode(config);
    }

    public ModificationMetrics getMetrics() {
        return metrics;
    }

    /**
     * 修改指标统计
     */
    public static class ModificationMetrics {
        private volatile long modifications = 0;
        private volatile long dictionaryWriters = 0;
        private volatile long standardWriters = 0;
        private volatile long errors = 0;
        private volatile long totalProcessingTime = 0;

        public void incrementModifications() { modifications++; }
        public void incrementDictionaryWriters() { dictionaryWriters++; }
        public void incrementStandardWriters() { standardWriters++; }
        public void incrementErrors() { errors++; }
        public void recordProcessingTime(long nanos) { totalProcessingTime += nanos; }

        // Getters
        public long getModifications() { return modifications; }
        public long getDictionaryWriters() { return dictionaryWriters; }
        public long getStandardWriters() { return standardWriters; }
        public long getErrors() { return errors; }
        public double getAverageProcessingTimeNanos() {
            return modifications > 0 ? (double) totalProcessingTime / modifications : 0.0;
        }
    }
}
